#include "sock_app.h"
#include "server_node.h"
#include "tcp_server.h"

CServerNode::CServerNode(int fd, int fd_poll, IIOMgr* io_mgr)
{
    m_fd = fd;
    m_epoll_events = EPOLLET;
    m_io_mgr = io_mgr;
    m_socket_is_closed = false;
    printf("CServerNode::CServerNode | a new object with fd %d is created\n", m_fd);
}

CServerNode::~CServerNode()
{
    printf("CServerNode::~CServerNode | object with fd %d is destoried\n", m_fd);
    if (!m_socket_is_closed){
        closeSocket();
    }
}

void CServerNode::enableRead(bool is_enable)
{
    if (m_socket_is_closed){
        return;
    }    
    if (is_enable)
        m_epoll_events |= EPOLLIN;
    else
        m_epoll_events &= ~EPOLLIN;
    epoll_event ev;
    ev.data.fd = m_fd;
    ev.events = m_epoll_events;
    printf("CServerNode::enableRead | fd %d %s\n", m_fd, is_enable ? "enabled" : "disalbed");
    CTCPServer::getInstance().epoll_update(EPOLL_CTL_MOD, m_fd, &ev);
    
}

void CServerNode::enableWrite(bool is_enable)
{
    if (m_socket_is_closed){
        return;
    }
    if (is_enable)
        m_epoll_events |= EPOLLOUT;
    else
        m_epoll_events &= ~EPOLLOUT;

    epoll_event ev;
    ev.data.fd = m_fd;
    ev.events = m_epoll_events;
    printf("CServerNode::enableWrite | fd %d %s\n", m_fd, is_enable ? "enabled" : "disalbed");
    CTCPServer::getInstance().epoll_update(EPOLL_CTL_MOD, m_fd, &ev);
}

void CServerNode::closeSocket()
{
    if (m_socket_is_closed){
        return;
    }
    m_epoll_events &= ~EPOLLOUT;
    m_epoll_events &= ~EPOLLIN;
    epoll_event ev;
    ev.data.fd = m_fd;
    ev.events = m_epoll_events;
    printf("CServerNode::closeSocket() | remove fd %d from epoll\n", m_fd);
    CTCPServer::getInstance().epoll_update(EPOLL_CTL_DEL, m_fd, &ev);
    printf("CServerNode::closeSocket() | close socket: %d\n", m_fd);
    close(m_fd);
    m_socket_is_closed = true;
}

void CServerNode::onAccept(sockaddr_in addr)
{
    m_addr = addr;
    m_epoll_events |= EPOLLIN;
    epoll_event ep_for_new_fd;
    ep_for_new_fd.data.fd = m_fd;
    //新创建的连接不监听EPOLLOUT事件，我们约定由客户端发送第一条数据。
    ep_for_new_fd.events = m_epoll_events;
    CTCPServer::getInstance().epoll_update(EPOLL_CTL_ADD, m_fd, &ep_for_new_fd);
    printf("CServerNode::onAccept() | add socket %d to epoll\n", m_fd);
    m_io_mgr->newSocketAccepted(shared_from_this());
}

void CServerNode::onSocketClosed()
{
    if (!m_socket_is_closed){
        // @TODO: 这里让IOManager关闭可能会好一些?
        // 有可能IOManager对这个socket还感兴趣。
        printf("CServerNode::onSocketClosed() | ..\n");
        closeSocket();
        m_socket_is_closed = true;
    }
    printf("CServerNode::onSocketClosed() | this socket: %d\n", m_fd);
    m_io_mgr->notifySocketClosed(shared_from_this());
}

void CServerNode::onSocketError(int error_code)
{
    if (!m_socket_is_closed){
        // @TODO: 这里让IOManager关闭可能会好一些? 
        // 如果在这里执行CServerNode::closeSocket()，那么IO Manager将无法收到socket错误的
        // 通知，因为closeSocket函数会将它从
        printf("CServerNode::onSocketError() | this socket was not closed, now close it.\n");
        closeSocket();
        m_socket_is_closed = true;
    }
    printf("CServerNode::onSocketError() | this socket: %d. err code: %d\n", m_fd, error_code);
    m_io_mgr->notifySocketError(shared_from_this(), error_code);
}

void CServerNode::onDataRecved(const string &data)
{
    if (data.empty())
        return;
    std::lock_guard<std::recursive_mutex> l(m_mutex_recv);
    m_recv_buffers.append(data);
    printf("CServerNode::onDataRecved() bytes %ld, total in buffer %ld\n", data.length(), m_recv_buffers.length());
    m_io_mgr->notifyDataRecvedEvent(shared_from_this());
}

void CServerNode::sendData(const string& data)
{
    if (data.empty())
        return;
    printf("CServerNode::sendData() bytes %ld, package count in buffer %ld\n", data.length(), m_send_buffers.size());
    std::lock_guard<std::recursive_mutex> l(m_mutex_send);
    m_send_buffers.push_back(data);
    enableWrite(true);
    // 大部分应用发送通知可以不用。
    //IOManager::getInstance()->notifyDataSentEvent(this);
}

void CServerNode::onSend()
{
    // m_internal_buf 保存上次未发送完成的数据。
    // 当发送大量数据的时候很常见，因为大小可能会超过网络发送缓冲区的可用容量。
    if (m_internal_buf.empty())
    {
        printf("情况1: 已无上次未发送完毕的数据。\n");
        string send_buf;
        getDataToSend(send_buf);
        if (send_buf.empty())
        {
            // 情况1: 无可发送数据
            printf("情况1.1: 无可发送数据\n");
            enableWrite(false);
            return;
        }
        int sn = send(m_fd, send_buf.data(), send_buf.length(), 0);
        if (sn == send_buf.length())
        {
            // 情况2: 全部发送完成。
            // 发送完成，不必监听是否可发送的消息了。
            // 等下次有数据要发送的时候再开启。
            printf("情况1.2: 全部发送完成。\n");
            enableWrite(false);
        }
        else if (sn <= 0)
        {
            // 情况3： 发生了发送错误。这种错误应极少出现。
            printf("情况1.3: 发生了发送错误 %d,暂停监听epoll可写信号。\n", sn);
            enableWrite(false);
            printf("清除未发送的数据并关闭socket.\n");
            m_internal_buf.clear();
            m_send_buffers.clear();
            //这里不能调用closeSocket();因为它会将fd从epoll列表中移除，导致会无法监听到断开消息。
            //照成ServerNode对象无法正常销毁。这里的做法是直接关闭socket，让epoll触发断开信号或者错误信号。
            //会重复导致整个fd被重复close，但是应该不会造成错误。
            close(m_fd);
        }
        else
        {
            // 情况4： 发送部分完成。
            // 发送缓冲区不足，只发送了部分。极少数发生，但不排除存在可能性。
            // 这种情况下等待下次事件通知就好了。
            printf("情况1.4: 发送部分完成。\n");
            m_internal_buf = send_buf.substr(sn);
        }
    }
    else
    {
        int sn = send(m_fd, m_internal_buf.data(), m_internal_buf.length(), 0);
        if (sn == m_internal_buf.length())
        {
            printf("已完成续发上次未完成的数据%d字节。\n", sn);
            if (m_send_buffers.empty()){
                printf("已无需要发送的数据,暂停监听epoll可写信号。\n");
                enableWrite(false);
            }
        }
        else if (sn <= 0)
        {
            // 发送错误处理。这种错误应极少出现。
            printf("发送错误 %d,暂停监听epoll可写信号。\n", sn);
            enableWrite(false);
            printf("清除未发送的数据并关闭socket.\n");
            m_internal_buf.clear();
            m_send_buffers.clear();
            //这里不能调用closeSocket();因为它会将fd从epoll列表中移除，导致会无法监听到断开消息。
            //照成ServerNode对象无法正常销毁。这里的做法是直接关闭socket，让epoll触发断开信号或者错误信号。
            //会重复导致整个fd被重复close，但是应该不会造成错误。
            close(m_fd);
        }
        else
        {
            printf("发送%d字节, 仍有部分缓存中的数据未发送完毕。\n", sn);
            m_internal_buf = m_internal_buf.substr(sn);
        }
    }
    m_io_mgr->notifyDataSentEvent(shared_from_this());
}

void CServerNode::getDataRecved(string& data){
    std::lock_guard<std::recursive_mutex> l(m_mutex_recv);
    data = m_recv_buffers;
    m_recv_buffers.clear();
}

void CServerNode::getDataToSend(string& data) 
{ 
    if (m_send_buffers.empty()){
        return;
    }
    // @TODO 合并发送？
    std::lock_guard<std::recursive_mutex> l(m_mutex_send);
    data = m_send_buffers.front();
    m_send_buffers.pop_front();
}
